package com.xyht.sca_s.student_manage_system.modules.assetConsumable.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.data.PictureRenderData;
import com.deepoove.poi.data.PictureType;
import com.deepoove.poi.data.Pictures;
import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
import com.deepoove.poi.policy.PictureRenderPolicy;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.spire.doc.Document;
import com.spire.doc.FileFormat;
import com.xyht.sca_s.student_manage_system.common.commonReturn.CommonCodeEnum;
import com.xyht.sca_s.student_manage_system.common.commonReturn.CommonResult;
import com.xyht.sca_s.student_manage_system.common.commonReturn.ExceptionCast;
import com.xyht.sca_s.student_manage_system.common.commonReturn.ResponseResult;
import com.xyht.sca_s.student_manage_system.common.util.ApiModelUtil;
import com.xyht.sca_s.student_manage_system.common.util.CacheUtil;
import com.xyht.sca_s.student_manage_system.common.util.TimeUtil;
import com.xyht.sca_s.student_manage_system.modules.asset.entity.SmsAssetCategoryManagement;
import com.xyht.sca_s.student_manage_system.modules.asset.entity.SmsAssetProcess;
import com.xyht.sca_s.student_manage_system.modules.asset.entity.SmsAssetProcessDetail;
import com.xyht.sca_s.student_manage_system.modules.asset.mapper.SmsAssetCategoryManagementMapper;
import com.xyht.sca_s.student_manage_system.modules.asset.mapper.SmsAssetProcessDetailMapper;
import com.xyht.sca_s.student_manage_system.modules.asset.mapper.SmsAssetProcessMapper;
import com.xyht.sca_s.student_manage_system.modules.asset.util.AssetUtil;
import com.xyht.sca_s.student_manage_system.modules.assetConsumable.constant.AssetAllowStatusConstant;
import com.xyht.sca_s.student_manage_system.modules.assetConsumable.entity.*;
import com.xyht.sca_s.student_manage_system.modules.assetConsumable.entity.req.SmsAssetConsumableInStorageApplyHistoryReq;
import com.xyht.sca_s.student_manage_system.modules.assetConsumable.entity.req.consumableInStorageApply.SmsAssetConsumableInStorageApplyAllowReq;
import com.xyht.sca_s.student_manage_system.modules.assetConsumable.entity.req.consumableInStorageApply.SmsAssetConsumableInStorageApplyGoodsReq;
import com.xyht.sca_s.student_manage_system.modules.assetConsumable.entity.req.consumableInStorageApply.SmsAssetConsumableInStorageApplyProcessDetailReq;
import com.xyht.sca_s.student_manage_system.modules.assetConsumable.entity.req.consumableInStorageApply.SmsAssetConsumableInStorageApplyReq;
import com.xyht.sca_s.student_manage_system.modules.assetConsumable.entity.resp.SmsConsumableInStorageApplyGoodsExportResp;
import com.xyht.sca_s.student_manage_system.modules.assetConsumable.entity.resp.consumableInStorageApply.SmsAssetConsumableInStorageApplyGoodsResp;
import com.xyht.sca_s.student_manage_system.modules.assetConsumable.entity.resp.consumableInStorageApply.SmsAssetConsumableInStorageApplyMPJResp;
import com.xyht.sca_s.student_manage_system.modules.assetConsumable.entity.resp.consumableInStorageApply.SmsAssetConsumableInStorageApplyProcessDetailResp;
import com.xyht.sca_s.student_manage_system.modules.assetConsumable.entity.resp.consumableInStorageApply.SmsAssetConsumableInStorageApplyResp;
import com.xyht.sca_s.student_manage_system.modules.assetConsumable.mapper.*;
import com.xyht.sca_s.student_manage_system.modules.assetConsumable.service.SmsAssetConsumableInStorageApplyService;
import com.xyht.sca_s.student_manage_system.modules.common.constant.FileSavePathConstant;
import com.xyht.sca_s.student_manage_system.modules.newTips.myEnum.AppTypeEnum;
import com.xyht.sca_s.student_manage_system.modules.newTips.myEnum.RangeTypeEnum;
import com.xyht.sca_s.student_manage_system.modules.newTips.myEnum.TipsTypeEnum;
import com.xyht.sca_s.student_manage_system.modules.newTips.util.NewTipsUtil;
import com.xyht.sca_s.student_manage_system.modules.user.entity.SmsRole;
import com.xyht.sca_s.student_manage_system.modules.user.entity.SmsUser;
import com.xyht.sca_s.student_manage_system.modules.user.entity.resp.SmsSearchUserResp;
import com.xyht.sca_s.student_manage_system.modules.user.mapper.SmsRoleMapper;
import com.xyht.sca_s.student_manage_system.modules.user.mapper.SmsUserMapper;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType0Font;
import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

import static com.xyht.sca_s.student_manage_system.common.constant.CommonConstant.APPLY_MAX_SIZE;
import static com.xyht.sca_s.student_manage_system.common.util.ParamCheckUtil.isNullOrEmpty;
import static com.xyht.sca_s.student_manage_system.modules.asset.constant.AssetAllowTypeConstant.*;
import static com.xyht.sca_s.student_manage_system.modules.asset.constant.AssetBooleanConstant.ASSET_BOOLEAN_FALSE;
import static com.xyht.sca_s.student_manage_system.modules.asset.constant.AssetBooleanConstant.ASSET_BOOLEAN_TRUE;
import static com.xyht.sca_s.student_manage_system.modules.asset.constant.AssetObjectTypeConstant.ASSET_OBJECT_TYPE_PERSON;
import static com.xyht.sca_s.student_manage_system.modules.asset.constant.AssetProcessTypeConstant.ASSET_PROCESS_TYPE_CONSUMABLE_IN_STORAGE;
import static com.xyht.sca_s.student_manage_system.modules.asset.constant.AssetStatusConstant.ASSET_STATUS_IN_STORAGE;
import static com.xyht.sca_s.student_manage_system.modules.asset.constant.InStorageMethodConstant.IN_STORAGE_METHOD_CONSUMABLE_APPLY;
import static com.xyht.sca_s.student_manage_system.modules.asset.constant.ProcessObjectTypeConstant.PROCESS_OBJECT_TYPE_PERSON;
import static com.xyht.sca_s.student_manage_system.modules.assetConsumable.constant.AssetAllowStatusConstant.*;
import static com.xyht.sca_s.student_manage_system.modules.assetConsumable.constant.InfrastructureIsExportProcessConstant.EXPORT_PROCESS_TRUE;
import static com.xyht.sca_s.student_manage_system.modules.examinePaymentEquipment.constant.paymentExamineStatusConstant.EXAMINE_STATUS_PASS;
import static com.xyht.sca_s.student_manage_system.modules.examinePaymentEquipment.constant.paymentExamineStatusConstant.EXAMINE_STATUS_WAIT_ALLOW;
import static com.xyht.sca_s.student_manage_system.modules.student.constant.StudentInfoCommonConstant.PER_SHEET_NUM;

/**
 * <p>
 * 低值易耗品入库申请 服务实现类
 * </p>
 *
 * @author XYHT
 * @since 2023-06-25
 */
@Service
public class SmsAssetConsumableInStorageApplyServiceImpl extends ServiceImpl<SmsAssetConsumableInStorageApplyMapper, SmsAssetConsumableInStorageApply> implements SmsAssetConsumableInStorageApplyService {
    @Resource
    private FileSavePathConstant fileSavePathConstant;
    @Autowired
    private SmsAssetConsumableInStorageApplyMapper smsAssetConsumableInStorageApplyMapper;
    @Autowired
    private SmsAssetProcessMapper smsAssetProcessMapper;
    @Autowired
    private SmsAssetProcessDetailMapper smsAssetProcessDetailMapper;
    @Autowired
    private SmsAssetCategoryManagementMapper smsAssetCategoryManagementMapper;
    @Autowired
    private SmsAssetConsumableInStorageApplyGoodsMapper smsAssetConsumableInStorageApplyGoodsMapper;
    @Autowired
    private SmsAssetConsumableInStorageApplyProcessDetailMapper smsAssetConsumableInStorageApplyProcessDetailMapper;
    @Autowired
    private NewTipsUtil newTipsUtil;
    @Autowired
    private CacheUtil cacheUtil;
    @Autowired
    private SmsAssetConsumableInStorageApplyProcessDetailMPJMapper smsAssetConsumableInStorageApplyProcessDetailMPJMapper;
    @Autowired
    private SmsAssetConsumableStorageMapper smsAssetConsumableStorageMapper;
    @Autowired
    private AssetUtil assetUtil;
    @Autowired
    private SmsUserMapper smsUserMapper;
    @Autowired
    private ApiModelUtil apiModelUtil;
    @Autowired
    private SmsRoleMapper smsRoleMapper;

    @Override
    @Transactional
    public ResponseResult addConsumableInStorageApply(SmsAssetConsumableInStorageApplyReq applyReq, String userId) {
        //校验前端传入参数
        if (isNullOrEmpty(applyReq.getApplyName()) || isNullOrEmpty(applyReq.getGoodsList()) || applyReq.getGoodsList().size() < 1) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }

        //判断当前申请人待审批状态下的申请是否过多
        Integer applyCount = smsAssetConsumableInStorageApplyMapper.selectCount(new LambdaQueryWrapper<SmsAssetConsumableInStorageApply>()
                .eq(SmsAssetConsumableInStorageApply::getApplyUserId, userId)
                .eq(SmsAssetConsumableInStorageApply::getAllowStatus, ASSET_ALLOW_STATUS_WAIT_ALLOW));
        if (applyCount >= APPLY_MAX_SIZE) {
            return CommonResult.failed(CommonCodeEnum.ASSET_APPLY_MAX_LIMIT);
        }

        //查询系统节点(易耗品入库)并判断是否合法
        SmsAssetProcess originProcess = smsAssetProcessMapper.selectOne(new LambdaQueryWrapper<SmsAssetProcess>()
                .eq(SmsAssetProcess::getProcessType, ASSET_PROCESS_TYPE_CONSUMABLE_IN_STORAGE));
        if (originProcess == null) {
            ExceptionCast.cast(CommonResult.failed(CommonCodeEnum.ASSET_PROCESS_NOT_SETTING));
        }
        //查询(易耗品入库)节点流程进行匹配,判断申请人是否设置完所有流程
        List<SmsAssetProcessDetail> systemProcessList = smsAssetProcessDetailMapper.selectList(new LambdaQueryWrapper<SmsAssetProcessDetail>()
                .eq(SmsAssetProcessDetail::getProcessDetailIsApplicantEdit, ASSET_BOOLEAN_TRUE)
                .eq(SmsAssetProcessDetail::getProcessDetailIsUse, ASSET_BOOLEAN_TRUE)
                .eq(SmsAssetProcessDetail::getProcessId, originProcess.getId())
                .orderByAsc(SmsAssetProcessDetail::getProcessDetailSort));
        if (systemProcessList != null && systemProcessList.size() > 0) {
            if (applyReq.getProcessList() == null || applyReq.getProcessList().size() < 1) {
                return CommonResult.failed(CommonCodeEnum.ASSET_ALLOW_USER_NOT_SETTING);
            }
            //判断申请人是否将全部需要编辑的流程填写完毕
            List<SmsAssetProcessDetail> filterList = systemProcessList.stream().filter(systemProcess -> {
                        //匹配的去除,未匹配的留下
                        List<SmsAssetConsumableInStorageApplyProcessDetailReq> result = applyReq.getProcessList().stream()
                                .filter(applyProcess -> applyProcess.getProcessDetailId().equals(systemProcess.getId()))
                                .collect(Collectors.toList());
                        //如果全部匹配,则 result.size() = 0
                        return result.size() == 0;
                    }
            ).collect(Collectors.toList());
            if (filterList.size() > 0) {
                return CommonResult.failed(CommonCodeEnum.ASSET_ALLOW_PROCESS_NOT_FILL);
            }
        }

        //创建申请表
        SmsAssetConsumableInStorageApply smsAssetConsumableInStorageApply = new SmsAssetConsumableInStorageApply();
        BeanUtils.copyProperties(applyReq, smsAssetConsumableInStorageApply);
        smsAssetConsumableInStorageApply.setApplyUserId(userId);
        smsAssetConsumableInStorageApply.setAllowStatus(ASSET_ALLOW_STATUS_WAIT_ALLOW);
        //获取当天批次数量,设置ApplySort
        String simpleDate = TimeUtil.DateSimpleformat(new Date());
        Integer count = smsAssetConsumableInStorageApplyMapper.selectCount(new LambdaQueryWrapper<SmsAssetConsumableInStorageApply>()
                .like(SmsAssetConsumableInStorageApply::getCreateTime, simpleDate));
        smsAssetConsumableInStorageApply.setApplySort(count + 1);
        smsAssetConsumableInStorageApplyMapper.insert(smsAssetConsumableInStorageApply);
        //判断是否插入成功
        String applyId = smsAssetConsumableInStorageApply.getId();
        if (applyId == null) {
            ExceptionCast.cast(CommonResult.failed(CommonCodeEnum.FAIL));
        }

        //创建入库申请物品记录
        for (SmsAssetConsumableInStorageApplyGoodsReq goodsReq : applyReq.getGoodsList()) {
            //校验物品是否正常传入
            if (isNullOrEmpty(goodsReq.getAssetBrand()) || isNullOrEmpty(goodsReq.getAssetCategory())
                    || isNullOrEmpty(goodsReq.getAssetModel()) || isNullOrEmpty(goodsReq.getAssetName())
                    || isNullOrEmpty(goodsReq.getAssetNum()) || isNullOrEmpty(goodsReq.getAssetPrice())) {
                ExceptionCast.cast(CommonResult.failed(CommonCodeEnum.INVALID_PARAM));
            }
            //校验分类是否合法
            SmsAssetCategoryManagement assetCategoryManagement = smsAssetCategoryManagementMapper.selectById(goodsReq.getAssetCategory());
            if (assetCategoryManagement == null || isNullOrEmpty(assetCategoryManagement.getId())) {
                ExceptionCast.cast(CommonResult.failed(CommonCodeEnum.ASSET_CATEGORY_NOT_EXIST));
            }
            //判断是否为根类别
            if (assetCategoryManagement.getId().length() < 3) {
                ExceptionCast.cast(CommonResult.failed(CommonCodeEnum.ASSET_CATEGORY_CAN_NOT_USE_ROOT));
            }
            //判断数量
            if (goodsReq.getAssetNum() <= 0) {
                ExceptionCast.cast(CommonResult.failed(CommonCodeEnum.ASSET_STORAGE_NUM_ERR));
            }

            SmsAssetConsumableInStorageApplyGoods smsAssetConsumableInStorageApplyGoods = new SmsAssetConsumableInStorageApplyGoods();
            BeanUtils.copyProperties(goodsReq, smsAssetConsumableInStorageApplyGoods);
            smsAssetConsumableInStorageApplyGoods.setApplyId(applyId);
            smsAssetConsumableInStorageApplyGoodsMapper.insert(smsAssetConsumableInStorageApplyGoods);
        }

        //创建审批流程
        //查询系统流程节点
        List<SmsAssetProcessDetail> systemProcessDetailList = smsAssetProcessDetailMapper.selectList(new LambdaQueryWrapper<SmsAssetProcessDetail>()
                .eq(SmsAssetProcessDetail::getProcessDetailIsUse, ASSET_BOOLEAN_TRUE)
                .eq(SmsAssetProcessDetail::getProcessId, originProcess.getId())
                .orderByAsc(SmsAssetProcessDetail::getProcessDetailSort));
        if (systemProcessDetailList == null || systemProcessDetailList.size() < 1) {
            ExceptionCast.cast(CommonResult.failed(CommonCodeEnum.ASSET_PROCESS_NOT_SETTING));
        }
        int sort = 1;
        for (SmsAssetProcessDetail process : systemProcessDetailList) {
            //判断管理员是否配置初始流程
            if (process.getProcessDetailIsApplicantEdit().equals(ASSET_BOOLEAN_FALSE)) {
                if (isNullOrEmpty(process.getProcessDetailObjectId()) || isNullOrEmpty(process.getProcessDetailObjectType())) {
                    ExceptionCast.cast(CommonResult.failed(CommonCodeEnum.ASSET_PROCESS_NOT_SETTING));
                }
            }

            SmsAssetConsumableInStorageApplyProcessDetail addDetail = new SmsAssetConsumableInStorageApplyProcessDetail();
            addDetail.setApplyId(applyId);
            addDetail.setProcessDetailId(process.getId());
            addDetail.setProcessDetailIsSign(process.getProcessDetailIsSign());
            addDetail.setProcessDetailIsStamp(process.getProcessDetailIsStamp());
            addDetail.setProcessDetailName(process.getProcessDetailName());
            addDetail.setProcessDetailStatus(ASSET_ALLOW_STATUS_WAIT_ALLOW);
            addDetail.setProcessDetailSort(sort++);

            //申请人可编辑流程
            if (process.getProcessDetailIsApplicantEdit().equals(ASSET_BOOLEAN_TRUE)) {
                List<SmsAssetConsumableInStorageApplyProcessDetailReq> filterList = applyReq.getProcessList().stream()
                        .filter(applyProcess -> applyProcess.getProcessDetailId().equals(process.getId()))
                        .collect(Collectors.toList());
                if (filterList.size() == 0) {
                    ExceptionCast.cast(CommonResult.failed(CommonCodeEnum.ASSET_ALLOW_PROCESS_NOT_FILL));
                }
                SmsAssetConsumableInStorageApplyProcessDetailReq filterProcessReq = filterList.get(0);
                if (isNullOrEmpty(filterProcessReq.getProcessDetailObjectId())) {
                    ExceptionCast.cast(CommonResult.failed(CommonCodeEnum.INVALID_PARAM));
                }
                addDetail.setProcessDetailObjectId(filterProcessReq.getProcessDetailObjectId());
                addDetail.setProcessDetailObjectType(ASSET_OBJECT_TYPE_PERSON);
            } else {
                addDetail.setProcessDetailObjectId(process.getProcessDetailObjectId());
                addDetail.setProcessDetailObjectType(process.getProcessDetailObjectType());
            }
            smsAssetConsumableInStorageApplyProcessDetailMapper.insert(addDetail);
        }

        //消息通知
        //通知流程第一个节点
        SmsAssetConsumableInStorageApplyProcessDetail firstDetail =
                smsAssetConsumableInStorageApplyProcessDetailMapper.selectOne(new LambdaQueryWrapper<SmsAssetConsumableInStorageApplyProcessDetail>()
                        .eq(SmsAssetConsumableInStorageApplyProcessDetail::getApplyId, applyId)
                        .eq(SmsAssetConsumableInStorageApplyProcessDetail::getProcessDetailSort, 1)
                        .orderByAsc(SmsAssetConsumableInStorageApplyProcessDetail::getProcessDetailSort));
        RangeTypeEnum rangeTypeEnum;
        if (firstDetail.getProcessDetailIsApplicantEdit() == ASSET_BOOLEAN_TRUE) {
            rangeTypeEnum = RangeTypeEnum.RANGE_TYPE_ENUM_PERSON;
        } else {
            if (firstDetail.getProcessDetailObjectType() == ASSET_OBJECT_TYPE_PERSON) {
                rangeTypeEnum = RangeTypeEnum.RANGE_TYPE_ENUM_PERSON;
            } else {
                rangeTypeEnum = RangeTypeEnum.RANGE_TYPE_ENUM_ROLE;
            }
        }

        List<String> rangeList = new ArrayList<>();
        rangeList.add(firstDetail.getProcessDetailObjectId());

        newTipsUtil.addNewTips(TipsTypeEnum.TIPS_TYPE_ENUM_ALLOW,
                userId,
                rangeTypeEnum,
                rangeList,
                AppTypeEnum.APP_TYPE_ENUM_ASSET,
                applyId,
                firstDetail.getId());

        return CommonResult.success();
    }

    @Override
    @Transactional
    public ResponseResult cancelConsumableInStorageApply(SmsAssetConsumableInStorageApplyReq cancelReq, String userId) {
        //校验前端参数
        if (isNullOrEmpty(cancelReq.getId())) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }

        //根据id获取入库申请表并校验
        SmsAssetConsumableInStorageApply assetApply = smsAssetConsumableInStorageApplyMapper.selectOne(new LambdaQueryWrapper<SmsAssetConsumableInStorageApply>()
                .eq(SmsAssetConsumableInStorageApply::getApplyUserId, userId)
                .eq(SmsAssetConsumableInStorageApply::getId, cancelReq.getId()));
        if (assetApply == null) {
            return CommonResult.failed(CommonCodeEnum.ASSET_APPLY_NOT_EXIST);
        }

        //若非待审批状态不可撤回
        if (assetApply.getAllowStatus() != EXAMINE_STATUS_WAIT_ALLOW) {
            return CommonResult.failed(CommonCodeEnum.ASSET_CANCEL_FAIL_ALLOWED);
        }

        //判断是否审批中
        List<SmsAssetConsumableInStorageApplyProcessDetail> detailList =
                smsAssetConsumableInStorageApplyProcessDetailMapper.selectList(new LambdaQueryWrapper<SmsAssetConsumableInStorageApplyProcessDetail>()
                        .eq(SmsAssetConsumableInStorageApplyProcessDetail::getApplyId, cancelReq.getId())
                        .eq(SmsAssetConsumableInStorageApplyProcessDetail::getProcessDetailStatus, EXAMINE_STATUS_PASS));
        if (detailList != null && detailList.size() > 0) {
            return CommonResult.failed(CommonCodeEnum.ASSET_CANCEL_FAIL_ALLOWING);
        }

        //撤回审批
        SmsAssetConsumableInStorageApply cancelApply = new SmsAssetConsumableInStorageApply();
        cancelApply.setId(cancelReq.getId());
        cancelApply.setAllowStatus(ASSET_ALLOW_STATUS_CANCEL);
        cancelApply.setEndTime(new Date());
        smsAssetConsumableInStorageApplyMapper.updateById(cancelApply);

        //修改节点状态
        SmsAssetConsumableInStorageApplyProcessDetail cancelProcessDetail = new SmsAssetConsumableInStorageApplyProcessDetail();
        cancelProcessDetail.setProcessDetailStatus(ASSET_ALLOW_STATUS_CANCEL);

        smsAssetConsumableInStorageApplyProcessDetailMapper.update(cancelProcessDetail, new LambdaQueryWrapper<SmsAssetConsumableInStorageApplyProcessDetail>()
                .eq(SmsAssetConsumableInStorageApplyProcessDetail::getApplyId, cancelReq.getId()));

        //消息通知
        newTipsUtil.cancelFinishTips(cancelReq.getId());
        return CommonResult.success();
    }

    @Override
    public ResponseResult getAssetConsumableInStorageApplyList(String userId, Integer applyType, Integer pageNum, Integer pageSize) {
        //校验前端参数
        if (isNullOrEmpty(applyType)) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }

        //构造回传数据
        List<SmsAssetConsumableInStorageApplyResp> respList = new ArrayList<>();
        int total = 0;

        //根据applyType进行相关处理
        if (applyType == ASSET_ALLOW_TYPE_APPLY) {//已发起
            Page<SmsAssetConsumableInStorageApply> page = new Page<>(pageNum, pageSize);
            LambdaQueryWrapper<SmsAssetConsumableInStorageApply> queryWrapper = new LambdaQueryWrapper<SmsAssetConsumableInStorageApply>()
                    .eq(SmsAssetConsumableInStorageApply::getApplyUserId, userId)
                    .orderByDesc(SmsAssetConsumableInStorageApply::getCreateTime);
            smsAssetConsumableInStorageApplyMapper.selectPage(page, queryWrapper);
            respList = page.getRecords().stream().map(apply -> {
                SmsAssetConsumableInStorageApplyResp applyResp = new SmsAssetConsumableInStorageApplyResp();
                BeanUtils.copyProperties(apply, applyResp);
                applyResp.setId(apply.getId());
                //获取当前用户信息并进行设置
                SmsUser smsUser = cacheUtil.getUserInfo(apply.getApplyUserId());
                SmsSearchUserResp userResp = new SmsSearchUserResp();
                if (smsUser != null) {
                    BeanUtils.copyProperties(smsUser, userResp);
                }
                applyResp.setApplyUserInfo(userResp);
                return applyResp;
            }).collect(Collectors.toList());
            total = (int) page.getTotal();
        } else if (applyType == ASSET_ALLOW_TYPE_ALLOWED) {//已办
            Page<SmsAssetConsumableInStorageApplyMPJResp> page = new Page<>(pageNum, pageSize);
            //SELECT * FROM sms_asset_consumable_in_storage_apply_process_detail LEFT JOIN sms_asset_consumable_in_storage_apply ON sms_asset_consumable_in_storage_apply.id = sms_asset_consumable_in_storage_apply_process_detail.apply_id WHERE sms_asset_consumable_in_storage_apply_process_detail.allow_user_id = '1670620062848978945' ORDER BY sms_asset_consumable_in_storage_apply.create_time, sms_asset_consumable_in_storage_apply_process_detail.end_time
            MPJLambdaWrapper<SmsAssetConsumableInStorageApplyProcessDetail> mpjLambdaWrapper = new MPJLambdaWrapper<>();
            mpjLambdaWrapper.selectAll(SmsAssetConsumableInStorageApplyProcessDetail.class).selectAll(SmsAssetConsumableInStorageApply.class)
                    .selectAs(SmsAssetConsumableInStorageApply::getCreateTime, "applyCreateTime")
                    .selectAs(SmsAssetConsumableInStorageApplyProcessDetail::getId, "detailId")
                    .leftJoin(SmsAssetConsumableInStorageApply.class, SmsAssetConsumableInStorageApply::getId, SmsAssetConsumableInStorageApplyProcessDetail::getApplyId)
                    .eq(SmsAssetConsumableInStorageApplyProcessDetail::getAllowUserId, userId)
                    .orderByDesc(SmsAssetConsumableInStorageApply::getCreateTime)
                    .orderByDesc(SmsAssetConsumableInStorageApplyProcessDetail::getEndTime);
            smsAssetConsumableInStorageApplyProcessDetailMPJMapper.selectJoinPage(page, SmsAssetConsumableInStorageApplyMPJResp.class, mpjLambdaWrapper);

            respList = page.getRecords().stream()
                    .map(smsMPJResp -> {
                        SmsAssetConsumableInStorageApplyResp applyResp = new SmsAssetConsumableInStorageApplyResp();
                        BeanUtils.copyProperties(smsMPJResp, applyResp);
                        applyResp.setCreateTime(smsMPJResp.getApplyCreateTime());
                        applyResp.setEndTime(smsMPJResp.getApplyEndTime());
                        applyResp.setId(smsMPJResp.getApplyId());

                        SmsUser applyUser = cacheUtil.getUserInfo(applyResp.getApplyUserId());
                        SmsSearchUserResp applyUserResp = new SmsSearchUserResp();
                        if (applyUser != null) {
                            BeanUtils.copyProperties(applyUser, applyUserResp);
                        }
                        applyResp.setApplyUserInfo(applyUserResp);

                        SmsUser allowUser = cacheUtil.getUserInfo(applyResp.getAllowUserId());
                        SmsSearchUserResp allowUserResp = new SmsSearchUserResp();
                        if (allowUser != null) {
                            BeanUtils.copyProperties(allowUser, allowUserResp);
                        }
                        applyResp.setAllowUserInfo(allowUserResp);
                        return applyResp;
                    }).collect(Collectors.toList());
            total = (int) page.getTotal();
        } else if (applyType == ASSET_ALLOW_TYPE_WAIT_ALLOW) {//待办
            List<String> roleList = cacheUtil.getRoleList(userId);

            //获取所有待审批申请流程节点
            List<SmsAssetConsumableInStorageApplyProcessDetail> allDetailList =
                    smsAssetConsumableInStorageApplyProcessDetailMapper.selectList(new LambdaQueryWrapper<SmsAssetConsumableInStorageApplyProcessDetail>()
                            .eq(SmsAssetConsumableInStorageApplyProcessDetail::getProcessDetailStatus, ASSET_ALLOW_STATUS_WAIT_ALLOW));

            List<SmsAssetConsumableInStorageApplyProcessDetail> filterDetailList = allDetailList.stream().filter(detail -> {
                if (detail.getProcessDetailIsApplicantEdit() == ASSET_BOOLEAN_TRUE) {
                    if (!detail.getProcessDetailObjectId().equals(userId)) {
                        return false;
                    }
                } else {
                    if (detail.getProcessDetailObjectType() == ASSET_OBJECT_TYPE_PERSON) {
                        if (!detail.getProcessDetailObjectId().equals(userId)) {
                            return false;
                        }
                    } else {
                        List<String> filterRoleList = roleList.stream().filter(role -> role.equals(detail.getProcessDetailObjectId())).collect(Collectors.toList());
                        if (filterRoleList.size() < 1) {
                            return false;
                        }
                    }
                }

                if (detail.getProcessDetailSort().equals(1)) {
                    return true;
                }

                //判断上一个流程节点是否完成
                SmsAssetConsumableInStorageApplyProcessDetail preDetail =
                        smsAssetConsumableInStorageApplyProcessDetailMapper.selectOne(new LambdaQueryWrapper<SmsAssetConsumableInStorageApplyProcessDetail>()
                                .eq(SmsAssetConsumableInStorageApplyProcessDetail::getApplyId, detail.getApplyId())
                                .eq(SmsAssetConsumableInStorageApplyProcessDetail::getProcessDetailSort, detail.getProcessDetailSort() - 1)
                                .eq(SmsAssetConsumableInStorageApplyProcessDetail::getProcessDetailStatus, ASSET_ALLOW_STATUS_PASS));
                if (preDetail == null || isNullOrEmpty(preDetail.getId())) {
                    return false;
                }
                return true;
            }).collect(Collectors.toList());

            if (filterDetailList.size() > 0) {//获取到当前用户待审批节点集合
                List<String> detailIDList = filterDetailList.stream().map(SmsAssetConsumableInStorageApplyProcessDetail::getId).collect(Collectors.toList());
                //SELECT * FROM sms_asset_consumable_in_storage_apply_process_detail LEFT JOIN sms_asset_consumable_in_storage_apply ON sms_asset_consumable_in_storage_apply.id = sms_asset_consumable_in_storage_apply_process_detail.apply_id WHERE sms_asset_consumable_in_storage_apply_process_detail.id IN 'detailIDList' ORDER BY DESC sms_asset_consumable_in_storage_apply.create_time, sms_asset_consumable_in_storage_apply_process_detail.create_time
                Page<SmsAssetConsumableInStorageApplyMPJResp> page = new Page<>(pageNum, pageSize);
                MPJLambdaWrapper<SmsAssetConsumableInStorageApplyProcessDetail> mpjLambdaWrapper = new MPJLambdaWrapper<>();
                mpjLambdaWrapper.selectAll(SmsAssetConsumableInStorageApplyProcessDetail.class).selectAll(SmsAssetConsumableInStorageApply.class)
                        .selectAs(SmsAssetConsumableInStorageApply::getCreateTime, "applyCreateTime")
                        .selectAs(SmsAssetConsumableInStorageApplyProcessDetail::getId, "detailId")
                        .leftJoin(SmsAssetConsumableInStorageApply.class, SmsAssetConsumableInStorageApply::getId, SmsAssetConsumableInStorageApplyProcessDetail::getApplyId)
                        .in(SmsAssetConsumableInStorageApplyProcessDetail::getId, detailIDList)
                        .orderByDesc(SmsAssetConsumableInStorageApply::getCreateTime)
                        .orderByDesc(SmsAssetConsumableInStorageApplyProcessDetail::getCreateTime);
                smsAssetConsumableInStorageApplyProcessDetailMPJMapper.selectJoinPage(page, SmsAssetConsumableInStorageApplyMPJResp.class, mpjLambdaWrapper);

                respList = page.getRecords().stream()
                        .map(smsApplyMPJResp -> {
                            SmsAssetConsumableInStorageApplyResp applyResp = new SmsAssetConsumableInStorageApplyResp();
                            BeanUtils.copyProperties(smsApplyMPJResp, applyResp);
                            applyResp.setCreateTime(smsApplyMPJResp.getApplyCreateTime());
                            applyResp.setId(smsApplyMPJResp.getApplyId());

                            SmsUser applyUser = cacheUtil.getUserInfo(smsApplyMPJResp.getApplyUserId());
                            SmsSearchUserResp smsExamineUserResp = new SmsSearchUserResp();
                            if (applyUser != null) {
                                BeanUtils.copyProperties(applyUser, smsExamineUserResp);
                            }
                            applyResp.setApplyUserInfo(smsExamineUserResp);
                            return applyResp;
                        }).collect(Collectors.toList());
                total = (int) page.getTotal();
            }
        }
        return CommonResult.success(respList, total);
    }

    @Override
    public ResponseResult getAssetConsumableInStorageApplyDetail(String applyId, String userId) {
        if (isNullOrEmpty(applyId)) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }
        SmsAssetConsumableInStorageApply assetApply = smsAssetConsumableInStorageApplyMapper.selectById(applyId);
        if (assetApply == null || isNullOrEmpty(assetApply.getId())) {
            return CommonResult.failed(CommonCodeEnum.ASSET_APPLY_NOT_EXIST);
        }

        SmsAssetConsumableInStorageApplyResp applyResp = new SmsAssetConsumableInStorageApplyResp();
        BeanUtils.copyProperties(assetApply, applyResp);
        //applyResp.setId(assetApply.getId());

        SmsUser smsUser = cacheUtil.getUserInfo(applyResp.getApplyUserId());
        SmsSearchUserResp smsUserResp = new SmsSearchUserResp();
        if (smsUser != null) {
            BeanUtils.copyProperties(smsUser, smsUserResp);
        }
        applyResp.setApplyUserInfo(smsUserResp);

        //封装流程节点
        List<SmsAssetConsumableInStorageApplyProcessDetailResp> detailRespList =
                smsAssetConsumableInStorageApplyProcessDetailMapper.selectList(new LambdaQueryWrapper<SmsAssetConsumableInStorageApplyProcessDetail>()
                                .eq(SmsAssetConsumableInStorageApplyProcessDetail::getApplyId, applyId)
                                .orderByAsc(SmsAssetConsumableInStorageApplyProcessDetail::getProcessDetailSort))
                        .stream()
                        .map(detail -> {
                            SmsAssetConsumableInStorageApplyProcessDetailResp detailResp = new SmsAssetConsumableInStorageApplyProcessDetailResp();
                            BeanUtils.copyProperties(detail, detailResp);
                            //如果有审批人,对审批人进行封装
                            if (!isNullOrEmpty(detailResp.getAllowUserId())) {
                                SmsUser userInfo = cacheUtil.getUserInfo(detailResp.getAllowUserId());
                                SmsSearchUserResp smsSearchUserResp = new SmsSearchUserResp();
                                if (userInfo != null) {
                                    BeanUtils.copyProperties(userInfo, smsSearchUserResp);
                                }
                                detailResp.setAllowUserInfo(smsSearchUserResp);
                            }
                            if(detail.getProcessDetailObjectType() == PROCESS_OBJECT_TYPE_PERSON){
                                SmsUser allowUser = cacheUtil.getUserInfo(detail.getProcessDetailObjectId());
                                if(allowUser != null) {
                                    detailResp.setObjectName(allowUser.getRealName());
                                    detailResp.setObjectPic(allowUser.getUserPic());
                                }
                            }else {
                                SmsRole smsRole = smsRoleMapper.selectById(detail.getProcessDetailObjectId());
                                if(smsRole != null) {
                                    detailResp.setObjectName(smsRole.getRoleName());
                                }
                            }
                            return detailResp;
                        }).collect(Collectors.toList());
        applyResp.setProcessList(detailRespList);

        //封装物品信息
        List<SmsAssetConsumableInStorageApplyGoodsResp> goodsList =
                smsAssetConsumableInStorageApplyGoodsMapper.selectList(new LambdaQueryWrapper<SmsAssetConsumableInStorageApplyGoods>()
                                .eq(SmsAssetConsumableInStorageApplyGoods::getApplyId, applyId))
                        .stream().map(goods -> {
                            SmsAssetConsumableInStorageApplyGoodsResp goodsResp = new SmsAssetConsumableInStorageApplyGoodsResp();
                            BeanUtils.copyProperties(goods, goodsResp);

                            SmsAssetCategoryManagement categoryManagement = smsAssetCategoryManagementMapper.selectById(goods.getAssetCategory());
                            if (categoryManagement != null) {
                                goodsResp.setAssetCategoryName(categoryManagement.getCategoryName());
                            }
                            return goodsResp;
                        }).collect(Collectors.toList());
        applyResp.setGoodsList(goodsList);
        return CommonResult.success(applyResp);
    }

    @Override
    @Transactional
    public ResponseResult allowAssetConsumableInStorageApply(SmsAssetConsumableInStorageApplyAllowReq allowReq, String userId) {
        //校验前端参数
        if (isNullOrEmpty(allowReq.getApplyId()) || isNullOrEmpty(allowReq.getDetailId()) || isNullOrEmpty(allowReq.getProcessDetailStatus())) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }

        //若传入参数非“通过”且非“驳回”,进行阻断
        if (allowReq.getProcessDetailStatus() != ASSET_ALLOW_STATUS_PASS && allowReq.getProcessDetailStatus() != ASSET_ALLOW_STATUS_DENY) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }

        //校验申请表是否存在
        SmsAssetConsumableInStorageApply inStorageApply = smsAssetConsumableInStorageApplyMapper.selectById(allowReq.getApplyId());
        if (inStorageApply == null || isNullOrEmpty(inStorageApply.getId())) {
            return CommonResult.failed(CommonCodeEnum.ASSET_APPLY_NOT_EXIST);
        }

        //校验该节点是否为“待审批”状态
        SmsAssetConsumableInStorageApplyProcessDetail processDetail =
                smsAssetConsumableInStorageApplyProcessDetailMapper.selectOne(new LambdaQueryWrapper<SmsAssetConsumableInStorageApplyProcessDetail>()
                        .eq(SmsAssetConsumableInStorageApplyProcessDetail::getApplyId, allowReq.getApplyId())
                        .eq(SmsAssetConsumableInStorageApplyProcessDetail::getId, allowReq.getDetailId())
                        .eq(SmsAssetConsumableInStorageApplyProcessDetail::getProcessDetailStatus, ASSET_ALLOW_STATUS_WAIT_ALLOW));
        if (processDetail == null || isNullOrEmpty(processDetail.getId())) {
            return CommonResult.failed(CommonCodeEnum.ASSET_ALLOW_FAIL);
        }

        //判断该节点是否本人审批(防止跳节点审批)
        if (processDetail.getProcessDetailObjectType() == ASSET_OBJECT_TYPE_PERSON) {
            if (!processDetail.getProcessDetailObjectId().equals(userId)) {
                return CommonResult.failed(CommonCodeEnum.ASSET_ALLOW_FAIL);
            }
        } else {
            List<String> roleList = cacheUtil.getRoleList(userId);
            List<String> filterRoleList = roleList.stream().filter(role -> role.equals(processDetail.getProcessDetailObjectId())).collect(Collectors.toList());
            if (filterRoleList.size() < 1) {
                return CommonResult.failed(CommonCodeEnum.ASSET_ALLOW_FAIL);
            }
        }

        //校验上一个节点状态是否为“通过”
        if (!processDetail.getProcessDetailSort().equals(1)) {
            SmsAssetConsumableInStorageApplyProcessDetail preDetail =
                    smsAssetConsumableInStorageApplyProcessDetailMapper.selectOne(new LambdaQueryWrapper<SmsAssetConsumableInStorageApplyProcessDetail>()
                            .eq(SmsAssetConsumableInStorageApplyProcessDetail::getApplyId, allowReq.getApplyId())
                            .eq(SmsAssetConsumableInStorageApplyProcessDetail::getProcessDetailSort, processDetail.getProcessDetailSort() - 1));
            if (preDetail != null && isNullOrEmpty(preDetail.getId())) {
                if (preDetail.getProcessDetailStatus() != ASSET_ALLOW_STATUS_PASS) {
                    return CommonResult.failed(CommonCodeEnum.ASSET_ALLOW_FAIL);
                }
            }
        }

        //修改ProcessDetail节点表
        SmsAssetConsumableInStorageApplyProcessDetail allowDetail = new SmsAssetConsumableInStorageApplyProcessDetail();
        allowDetail.setId(allowReq.getDetailId());
        allowDetail.setProcessDetailStatus(allowReq.getProcessDetailStatus());
        if (!isNullOrEmpty(allowReq.getProcessDetailRemark())) {
            allowDetail.setProcessDetailRemark(allowReq.getProcessDetailRemark());
        }
        Date nowDate = new Date();
        allowDetail.setEndTime(nowDate);
        allowDetail.setAllowUserId(userId);
        //设置签名
        if (processDetail.getProcessDetailIsSign() == ASSET_BOOLEAN_TRUE) {
            if (isNullOrEmpty(allowReq.getProcessDetailSign())) {
                return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
            }
            allowDetail.setProcessDetailSign(allowReq.getProcessDetailSign());
        }
        //设置印章
        if (processDetail.getProcessDetailIsStamp() == ASSET_BOOLEAN_TRUE) {
            if (isNullOrEmpty(allowReq.getProcessDetailStamp())) {
                return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
            }
            allowDetail.setProcessDetailStamp(allowReq.getProcessDetailStamp());
        }
        smsAssetConsumableInStorageApplyProcessDetailMapper.updateById(allowDetail);

        //流程是否结束标志
        boolean is_done = false;

        //判断是否最后一个节点/是否驳回
        Integer detailCount = smsAssetConsumableInStorageApplyProcessDetailMapper.selectCount(new LambdaQueryWrapper<SmsAssetConsumableInStorageApplyProcessDetail>()
                .eq(SmsAssetConsumableInStorageApplyProcessDetail::getApplyId, allowReq.getApplyId()));
        if (detailCount.equals(processDetail.getProcessDetailSort()) || allowReq.getProcessDetailStatus() == ASSET_ALLOW_STATUS_DENY) {
            is_done = true;//流程结束
            //修改申请表
            SmsAssetConsumableInStorageApply updateApply = new SmsAssetConsumableInStorageApply();
            updateApply.setId(allowReq.getApplyId());
            updateApply.setEndTime(nowDate);
            updateApply.setAllowStatus(allowReq.getProcessDetailStatus());
            smsAssetConsumableInStorageApplyMapper.updateById(updateApply);
        }

        //流程结束且同意,预生成资产加入资产库
        if (detailCount.equals(processDetail.getProcessDetailSort()) && allowReq.getProcessDetailStatus() == ASSET_ALLOW_STATUS_PASS) {
            List<SmsAssetConsumableInStorageApplyGoods> goodsList =
                    smsAssetConsumableInStorageApplyGoodsMapper.selectList(new LambdaQueryWrapper<SmsAssetConsumableInStorageApplyGoods>()
                            .eq(SmsAssetConsumableInStorageApplyGoods::getApplyId, allowReq.getApplyId()));
            if (goodsList != null && goodsList.size() > 0) {
                for (SmsAssetConsumableInStorageApplyGoods goods : goodsList) {
                    try {
                        //根据物品生成资产id
                        String categoryId = goods.getAssetCategory();
                        //形成物品id
                        String assetId = assetUtil.createAssetStorageID(categoryId,
                                new Date(),
                                IN_STORAGE_METHOD_CONSUMABLE_APPLY,
                                inStorageApply.getApplySort());
                        //创建物品(易耗品)
                        SmsAssetConsumableStorage addAsset = new SmsAssetConsumableStorage();
                        addAsset.setId(assetId);
                        addAsset.setConsumableCategory(goods.getAssetCategory());
                        addAsset.setConsumableNum(goods.getAssetNum());
                        addAsset.setAddUserId(inStorageApply.getApplyUserId());
                        addAsset.setConsumableStatus(ASSET_STATUS_IN_STORAGE);
                        addAsset.setConsumableBrand(goods.getAssetBrand());
                        addAsset.setConsumableModel(goods.getAssetModel());
                        addAsset.setConsumableName(goods.getAssetName());
                        addAsset.setConsumablePrice(goods.getAssetPrice());
                        addAsset.setConsumableSupplier(inStorageApply.getApplySupplier());
                        addAsset.setConsumableWarehouse(goods.getWarehouse());
                        //设置总价
                        Integer consumableNum = goods.getAssetNum();
                        BigDecimal totalPrice = goods.getAssetPrice().multiply(BigDecimal.valueOf(consumableNum));
                        addAsset.setTotalPrice(totalPrice);
                        smsAssetConsumableStorageMapper.insert(addAsset);
                    } catch (Exception e) {
                        e.printStackTrace();
                        ExceptionCast.cast(CommonResult.failed(CommonCodeEnum.FAIL));
                    }
                }
            }
        }

        //节点驳回 重置其余节点状态
        if (allowReq.getProcessDetailStatus() == ASSET_ALLOW_STATUS_DENY) {
            SmsAssetConsumableInStorageApplyProcessDetail updateDenyDetail = new SmsAssetConsumableInStorageApplyProcessDetail();
            updateDenyDetail.setProcessDetailStatus(ASSET_ALLOW_STATUS_DENY_FINISH);
            smsAssetConsumableInStorageApplyProcessDetailMapper.update(updateDenyDetail, new LambdaQueryWrapper<SmsAssetConsumableInStorageApplyProcessDetail>()
                    .eq(SmsAssetConsumableInStorageApplyProcessDetail::getApplyId, allowReq.getApplyId())
                    .eq(SmsAssetConsumableInStorageApplyProcessDetail::getProcessDetailStatus, ASSET_ALLOW_STATUS_WAIT_ALLOW));
        }

        //消息通知
        if (is_done) {//流程结束
            boolean result_status = false;//流程状态
            if (allowReq.getProcessDetailStatus() == ASSET_ALLOW_STATUS_PASS) {
                result_status = true;
            }
            newTipsUtil.allowFinishTips(allowReq.getApplyId(), userId, result_status);
        } else {
            SmsAssetConsumableInStorageApplyProcessDetail nextDetail =
                    smsAssetConsumableInStorageApplyProcessDetailMapper.selectOne(new LambdaQueryWrapper<SmsAssetConsumableInStorageApplyProcessDetail>()
                            .eq(SmsAssetConsumableInStorageApplyProcessDetail::getApplyId, allowReq.getApplyId())
                            .eq(SmsAssetConsumableInStorageApplyProcessDetail::getProcessDetailSort, processDetail.getProcessDetailSort() + 1));
            RangeTypeEnum rangeTypeEnum;
            if (nextDetail.getProcessDetailIsApplicantEdit() == ASSET_BOOLEAN_TRUE) {
                rangeTypeEnum = RangeTypeEnum.RANGE_TYPE_ENUM_PERSON;
            } else {
                if (nextDetail.getProcessDetailObjectType() == ASSET_OBJECT_TYPE_PERSON) {
                    rangeTypeEnum = RangeTypeEnum.RANGE_TYPE_ENUM_PERSON;
                } else {
                    rangeTypeEnum = RangeTypeEnum.RANGE_TYPE_ENUM_ROLE;
                }
            }

            List<String> rangeIDList = new ArrayList<>();
            rangeIDList.add(nextDetail.getProcessDetailObjectId());
            newTipsUtil.allowContinueTips(allowReq.getApplyId(),
                    userId,
                    rangeTypeEnum,
                    rangeIDList,
                    nextDetail.getId());
        }
        return CommonResult.success();
    }

    @Override
    @Async
    public Future<ResponseResult> tableDownload(String applyId, HttpServletResponse response) {
        SmsAssetConsumableInStorageApply apply = smsAssetConsumableInStorageApplyMapper.selectById(applyId);
        //校验入库申请表是否存在
        if (apply == null || apply.getId() == null) {
            return new AsyncResult<>(CommonResult.failed(CommonCodeEnum.IN_STORAGE_APPLICATION_NOT_EXIST));
        }
        //如果申请表为“待审批”状态,进行阻断
        if (apply.getAllowStatus() == AssetAllowStatusConstant.ASSET_ALLOW_STATUS_WAIT_ALLOW) {
            return new AsyncResult<>(CommonResult.failed(CommonCodeEnum.WORK_APPLICATION_DOWNLOAD_FAIL));
        }
        //根据系统拼接下载路径
        String filePath = System.getProperty("os.name").toLowerCase().startsWith("win") ? fileSavePathConstant.getFILE_DOWNLOAD_PATH()
                : fileSavePathConstant.getFILE_DOWNLOAD_PATH_LINUX();

        String docFilePath = filePath + applyId + ".docx";
        String pdfFilePath = filePath + applyId + ".pdf";

        File pdfFile = new File(pdfFilePath);
        if (!pdfFile.exists()) {
            try {
                Map<String, Object> templateMap = new HashMap<>();
                List<String> picTagList = new ArrayList<>();
                //设置applyTitle
                String applyTitle = "易耗品入库";
                templateMap.put("applyTitle", applyTitle);
                //设置applyUser,applyName,applyRemark
                SmsUser user = smsUserMapper.selectById(apply.getApplyUserId());
                if (user != null) {
                    templateMap.put("applyUser", user.getRealName());
                }
                templateMap.put("applyName", filterResultNull(apply.getApplyName()));
                templateMap.put("applyRemark", filterResultNull(apply.getApplyRemark()));

                //封装附件
                List<Map<String, Object>> fileList = new ArrayList<>();
                if (!isNullOrEmpty(apply.getApplyAttachment())) {
                    List<SmsCommonConsumableFileEntity> consumableFileEntityList = JSONObject.parseArray(
                            apply.getApplyAttachment(), SmsCommonConsumableFileEntity.class);
                    if (consumableFileEntityList != null && consumableFileEntityList.size() > 0) {
                        for (SmsCommonConsumableFileEntity fileEntity : consumableFileEntityList) {
                            String[] splitStr = fileEntity.getUrl().split("=");
                            String fileName = splitStr[splitStr.length - 1];

                            Map<String, Object> fileMap = new HashMap<>();
                            fileMap.put("attachment", fileName);
                            fileList.add(fileMap);
                        }
                    }
                    if (fileList.size() > 0) {
                        templateMap.put("attachmentList", fileList);
                    }
                }

                //获取审批流程
                List<SmsAssetConsumableInStorageApplyProcessDetail> processList = smsAssetConsumableInStorageApplyProcessDetailMapper.selectList(new LambdaQueryWrapper<SmsAssetConsumableInStorageApplyProcessDetail>()
                        .eq(SmsAssetConsumableInStorageApplyProcessDetail::getApplyId, applyId));
                List<SmsCommonConsumableProcessEntity> processEntityList = new ArrayList<>();
                if (processList != null && processList.size() > 0) {
                    for (SmsAssetConsumableInStorageApplyProcessDetail process : processList) {
                        if (process.getProcessDetailStatus() == ASSET_ALLOW_STATUS_PASS || process.getProcessDetailStatus() == ASSET_ALLOW_STATUS_DENY) {
                            SmsCommonConsumableProcessEntity processEntity = new SmsCommonConsumableProcessEntity();

                            SmsUser smsUser = smsUserMapper.selectById(process.getAllowUserId());
                            if (smsUser != null) {
                                processEntity.setAllowUserName(smsUser.getRealName());
                            }

                            if (process.getProcessDetailStatus() == ASSET_ALLOW_STATUS_PASS) {
                                processEntity.setAllowStatus("同意");
                            } else {
                                processEntity.setAllowStatus("拒绝");
                            }

                            //添加签名
                            if (isNullOrEmpty(process.getProcessDetailSign())) {
                                templateMap.put("allowSign", "");
                            } else {
                                String[] splitStr = process.getProcessDetailSign().split("=");
                                String fileName = splitStr[splitStr.length - 1];
                                File file = new File(filePath + fileName);
                                InputStream inputStream = new FileInputStream(file);
                                PictureRenderData pictures = Pictures.ofStream(inputStream, PictureType.PNG).size(60, 30).create();

                                processEntity.setAllowSign(pictures);

                                templateMap.put("allowSign", pictures);
                                picTagList.add("allowSign");
                            }

                            //添加印章
                            if (isNullOrEmpty(process.getProcessDetailStamp())) {
                                templateMap.put("allowStamp", "");
                            } else {
                                String[] splitStr = process.getProcessDetailStamp().split("=");
                                String fileName = splitStr[splitStr.length - 1];
                                File file = new File(filePath + fileName);
                                InputStream inputStream = new FileInputStream(file);
                                PictureRenderData pictures = Pictures.ofStream(inputStream,
                                        PictureType.PNG).size(60, 30).create();

                                processEntity.setAllowStamp(pictures);

                                templateMap.put("allowStamp", pictures);
                                picTagList.add("allowStamp");
                            }

                            processEntity.setAllowOpinion(filterResultNull(process.getProcessDetailRemark()));
                            if (process.getEndTime() != null) {
                                processEntity.setAllowTime(TimeUtil.DateHanZiSimpleFormat(process.getEndTime()));
                            }
                            processEntityList.add(processEntity);
                        }
                    }
                    if (processEntityList.size() > 0) {
                        templateMap.put("allowUserList", processEntityList);
                    }
                }

                //封装物品信息
                List<SmsAssetConsumableInStorageApplyGoods> applyGoodsList = smsAssetConsumableInStorageApplyGoodsMapper.selectList(
                        new LambdaQueryWrapper<SmsAssetConsumableInStorageApplyGoods>().eq(SmsAssetConsumableInStorageApplyGoods::getApplyId, applyId));
                List<SmsCommonConsumableGoodsEntity> goodsList = new ArrayList<>();
                for (SmsAssetConsumableInStorageApplyGoods applyGoods : applyGoodsList) {
                    SmsCommonConsumableGoodsEntity goods = new SmsCommonConsumableGoodsEntity();
                    BeanUtils.copyProperties(applyGoods, goods);
                    goods.setAssetPrice(String.valueOf(applyGoods.getAssetPrice()));
                    goods.setAssetNum(String.valueOf(applyGoods.getAssetNum()));
                    goods.setSupplier(smsAssetConsumableInStorageApplyMapper.selectById(applyGoods.getApplyId()).getApplySupplier());
                    goodsList.add(goods);
                }
                templateMap.put("goodsList", goodsList);

                ClassPathResource resource = new ClassPathResource("applyTemplates/consumableTemplate.docx");
                InputStream is = resource.getInputStream();
                FileOutputStream outputStream = new FileOutputStream(docFilePath);

                XWPFTemplate template = XWPFTemplate.compile(is);

                //配置循环表格
                Configure config = template.getConfig();
                for (String tag : picTagList) {
                    config.customPolicy(tag, new PictureRenderPolicy());
                }
                config.customPolicy("allowUserList", new LoopRowTableRenderPolicy());
                config.customPolicy("goodsList", new LoopRowTableRenderPolicy());

                template.render(templateMap);
                template.write(outputStream);

                is.close();
                outputStream.close();
                template.close();

                //word转pdf
                File destOri = new File(docFilePath);
                FileInputStream fileInputStream = new FileInputStream(destOri);
                FileOutputStream fileOutputStream = new FileOutputStream(pdfFilePath);

                Document document = new Document();
                document.loadFromStream(fileInputStream, FileFormat.Docx);
                //保存为PDF
                document.saveToFile(pdfFilePath, FileFormat.PDF);

                fileInputStream.close();
                fileOutputStream.close();
                document.close();

                log.debug("文件生成完成!");
            } catch (Exception e) {
                e.printStackTrace();
                return new AsyncResult<>(CommonResult.failed(CommonCodeEnum.FAIL));
            }
        }
        try {
            // 加载PDF文档
            PDDocument doc = PDDocument.load(pdfFile);
            doc.setAllSecurityToBeRemoved(true);
            // 创建水印
            String watermark = "南充电影工业职业学院";
            PDPageContentStream contentStream;

            for (PDPage page : doc.getPages()) {
                contentStream = new PDPageContentStream(doc, page, PDPageContentStream.AppendMode.APPEND, true, true);

                //加载字体
                ClassPathResource resource = new ClassPathResource("fonts/123.ttf");
                InputStream is = resource.getInputStream();
                PDFont font = PDType0Font.load(doc, is);

                int startX = 0; // 起始位置 x 坐标
                int startY = 0; // 起始位置 y 坐标
                float angle = -45; // 角度
                float interval = 220; // 间隔
                float opacity = 0.3f; // 透明度
                int colorR = 127; // 颜色 red 值
                int colorG = 127; // 颜色 green 值
                int colorB = 127; // 颜色 blue 值

                //透明的
                PDExtendedGraphicsState r0 = new PDExtendedGraphicsState();
                r0.setNonStrokingAlphaConstant(opacity);
                r0.setAlphaSourceFlag(true);
                contentStream.setGraphicsStateParameters(r0);

                //水印颜色
                contentStream.setNonStrokingColor(colorR, colorG, colorB);
                contentStream.beginText();
                contentStream.setFont(font, 30f);

                int xTimes = (int) Math.ceil(page.getMediaBox().getWidth() / interval);
                int yTimes = (int) Math.ceil(page.getMediaBox().getHeight() / interval);
                for (int x = startX; x <= xTimes; x++) {
                    for (int y = startY; y <= yTimes; y++) {
                        contentStream.setTextRotation(angle, (x * interval), (y * interval));
                        contentStream.showText(watermark);
                    }
                }
                contentStream.endText();
                contentStream.restoreGraphicsState();
                contentStream.close();
                is.close();
            }

//            response.reset();
            response.setCharacterEncoding("utf-8");
            response.setContentType("application/vnd.pdf;charset=utf-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("易耗品入库申请表预览.pdf", "utf-8"));
            response.setHeader("file-type", "download");
            response.setHeader("file-name", URLEncoder.encode("易耗品入库申请表预览.pdf", "utf-8"));
            response.setHeader("Access-Control-Expose-Headers", "file-type,file-name");
            //刷新缓冲
            response.flushBuffer();

            // 保存PDF文档
            doc.save(response.getOutputStream());
            doc.close();
        } catch (Exception e) {
            e.printStackTrace();
            return new AsyncResult<>(CommonResult.failed(CommonCodeEnum.FAIL));

        }
        return null;
    }

    @Override
    @Async
    public Future<ResponseResult> exportAllApplyList(SmsAssetConsumableInStorageApplyHistoryReq historyReq, HttpServletResponse response) {
        if (isNullOrEmpty(historyReq.getIsExportProcess())) {
            return new AsyncResult<>(CommonResult.failed(CommonCodeEnum.INVALID_PARAM));
        }
        try {
            //根据前端传参构造查询条件
            LambdaQueryWrapper<SmsAssetConsumableInStorageApply> inStorageApplyQueryWrapper = new LambdaQueryWrapper<>();
            if (!isNullOrEmpty(historyReq.getApplyId())) {
                inStorageApplyQueryWrapper.eq(SmsAssetConsumableInStorageApply::getId, historyReq.getApplyId());
            }
            if (!isNullOrEmpty(historyReq.getAllowStatus())) {
                inStorageApplyQueryWrapper.eq(SmsAssetConsumableInStorageApply::getAllowStatus, historyReq.getAllowStatus());
            }
            if (!isNullOrEmpty(historyReq.getApplyUser())) {
                List<String> userIds = smsUserMapper.selectList(new LambdaQueryWrapper<SmsUser>()
                                .like(SmsUser::getRealName, historyReq.getApplyUser()))
                        .stream()
                        .map(SmsUser::getId).collect(Collectors.toList());
                if (userIds.size() > 0) {
                    inStorageApplyQueryWrapper.in(SmsAssetConsumableInStorageApply::getApplyUserId, userIds);
                }
            }
            inStorageApplyQueryWrapper.orderByDesc(SmsAssetConsumableInStorageApply::getCreateTime);

            List<SmsAssetConsumableInStorageApply> applyList = smsAssetConsumableInStorageApplyMapper.selectList(inStorageApplyQueryWrapper);

            List<String> applyIdList = applyList.stream()
                    .map(SmsAssetConsumableInStorageApply::getId)
                    .collect(Collectors.toList());

            List<SmsConsumableInStorageApplyGoodsExportResp> goodsList = smsAssetConsumableInStorageApplyGoodsMapper.selectList(new LambdaQueryWrapper<SmsAssetConsumableInStorageApplyGoods>()
                            .in(SmsAssetConsumableInStorageApplyGoods::getApplyId, applyIdList)
                            .orderByDesc(SmsAssetConsumableInStorageApplyGoods::getCreateTime))
                    .stream()
                    .map(goods -> {
                        SmsConsumableInStorageApplyGoodsExportResp exportResp = new SmsConsumableInStorageApplyGoodsExportResp();
                        BeanUtils.copyProperties(goods, exportResp);

                        List<SmsAssetConsumableInStorageApply> filterList = applyList.stream()
                                .filter(inStorageApply -> exportResp.getApplyId().equals(inStorageApply.getId())).collect(Collectors.toList());
                        SmsAssetConsumableInStorageApply apply = filterList.get(0);
                        BeanUtils.copyProperties(apply, exportResp);

                        SmsUser smsUser = smsUserMapper.selectById(apply.getApplyUserId());
                        if (smsUser != null) {
                            exportResp.setApplyUser(smsUser.getRealName());
                        }
                        return exportResp;
                    }).collect(Collectors.toList());


            //表头数据
//            String[] header = historyReq.getLimitColumn().toArray(new String[0]);
            double sheetNum;
            //声明一个工作簿
            HSSFWorkbook workbook = new HSSFWorkbook();
            if (goodsList != null && goodsList.size() > 0) {
                sheetNum = Math.ceil((double) goodsList.size() / PER_SHEET_NUM);
                for (int k = 0; k < sheetNum; k++) {
                    //生成一个表格，设置表格名称为"易耗品入库申请记录导出表"
                    HSSFSheet sheet = workbook.createSheet("易耗品入库申请记录导出表" + (k + 1));

                    //设置表格列宽度为10个字节
                    sheet.setDefaultColumnWidth(12);
                    //创建标题的显示样式
                    HSSFCellStyle headerStyle = workbook.createCellStyle();
                    headerStyle.setFillForegroundColor(IndexedColors.YELLOW.index);
                    headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);

                    HSSFFont f = workbook.createFont();
                    f.setFontHeightInPoints((short) 10);//字号
                    f.setBold(true);//加粗
                    headerStyle.setFont(f);
                    //创建第一行表头
                    HSSFRow headRow = sheet.createRow(0);

                    //遍历添加表头
//                    String[] definedHeader = {"申请表id","申请时间","申请人","物品名称","单位","请购数量","用途","备注"};
                    String[] header = historyReq.getLimitColumn().toArray(new String[0]);
                    for (int i = 0; i < header.length + 1; i++) {
                        //创建一个单元格
                        HSSFCell cell = headRow.createCell(i);

                        if (i == 0) {
                            //创建一个内容对象
                            HSSFRichTextString text = new HSSFRichTextString("序号");
                            //将内容对象的文字内容写入到单元格中
                            cell.setCellValue(text);
                            cell.setCellStyle(headerStyle);
                            continue;
                        }
                        //创建一个内容对象
                        String header1 = apiModelUtil.getFieldValueByFieldName(SmsConsumableInStorageApplyGoodsExportResp.class, header[i - 1]);
                        HSSFRichTextString text = new HSSFRichTextString(header1);

                        //将内容对象的文字内容写入到单元格中
                        cell.setCellValue(text);
                        cell.setCellStyle(headerStyle);
                    }

                    //判断是否需要添加流程表头
                    if (historyReq.getIsExportProcess() == EXPORT_PROCESS_TRUE) {
                        HSSFCell cell = headRow.createCell(header.length + 1);

                        HSSFRichTextString text = new HSSFRichTextString("审批流程");

                        //将内容对象的文字内容写入到单元格中
                        cell.setCellValue(text);
                        cell.setCellStyle(headerStyle);
                    }

                    int range = PER_SHEET_NUM;
                    if (k + 1 == sheetNum) {
                        range = goodsList.size() - (PER_SHEET_NUM) * k;
                    }
                    for (int i = 0; i < range; i++) {
                        //创建一行
                        HSSFRow row1 = sheet.createRow(i + 1);
                        SmsConsumableInStorageApplyGoodsExportResp exportVo = goodsList.get((PER_SHEET_NUM) * k + i);
                        Map map = JSONObject.parseObject(JSON.toJSONString(exportVo), Map.class);
                        row1.createCell(0).setCellValue(new HSSFRichTextString(i + 1 + ""));
                        for (int j = 0; j < header.length; j++) {
                            String rowContent = "";
                            if (map.get(header[j]) instanceof Long) {
                                rowContent = TimeUtil.DateHanZiSimpleTimestamp((long) map.get(header[j]));
                            } else {
                                rowContent = String.valueOf(map.get(header[j]));
                            }
                            row1.createCell(j + 1).setCellValue(new HSSFRichTextString(rowContent));
                        }

                        if (historyReq.getIsExportProcess() == EXPORT_PROCESS_TRUE) {//需要输出流程
                            List<SmsAssetConsumableInStorageApplyProcessDetail> detailList =
                                    smsAssetConsumableInStorageApplyProcessDetailMapper.selectList(new LambdaQueryWrapper<SmsAssetConsumableInStorageApplyProcessDetail>()
                                            .eq(SmsAssetConsumableInStorageApplyProcessDetail::getApplyId, exportVo.getApplyId()));
                            StringBuilder stringBuilder = new StringBuilder();
                            if (detailList != null && detailList.size() > 0) {
                                int sort = 1;
                                for (SmsAssetConsumableInStorageApplyProcessDetail detail : detailList) {
                                    if (detail.getProcessDetailStatus() != ASSET_ALLOW_STATUS_PASS && detail.getProcessDetailStatus() != ASSET_ALLOW_STATUS_DENY) {
                                        sort += 1;
                                        break;
                                    }
                                    stringBuilder.append("审批节点").append(sort).append(":\n");

                                    SmsUser smsUser = smsUserMapper.selectById(detail.getProcessDetailObjectId());
                                    if (smsUser == null) {
                                        stringBuilder.append("审批人：").append("\n");
                                    } else {
                                        stringBuilder.append("审批人：").append(smsUser.getRealName()).append("\n");
                                    }

                                    if (detail.getProcessDetailStatus() == ASSET_ALLOW_STATUS_PASS) {
                                        stringBuilder.append("审批状态：同意").append("\n");
                                    } else {
                                        stringBuilder.append("审批状态：拒绝").append("\n");
                                    }

                                    if (isNullOrEmpty(detail.getProcessDetailRemark())) {
                                        stringBuilder.append("审批意见：").append("\n");
                                    } else {
                                        stringBuilder.append("审批意见：").append(detail.getProcessDetailRemark()).append("\n");
                                    }

                                    if (isNullOrEmpty(detail.getEndTime())) {
                                        stringBuilder.append("审批时间：").append("\n");
                                    } else {
                                        stringBuilder.append("审批时间：").append(TimeUtil.DateHanZiSimpleFormat(detail.getEndTime()))
                                                .append("\n").append("\n");
                                    }
                                    sort++;
                                }
                            }
                            row1.createCell(header.length + 1).setCellValue(new HSSFRichTextString(stringBuilder.toString()));
                        }
                    }
                }
            }

//            response.reset();
            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("易耗品入库申请记录导出表.xlsx", "utf-8"));
            response.setCharacterEncoding("utf-8");
            response.setHeader("file-type", "download");
            response.setHeader("file-name", URLEncoder.encode("易耗品入库申请记录导出表.xlsx", "utf-8"));
            response.setHeader("Access-Control-Expose-Headers", "file-type,file-name");
            //刷新缓冲
            response.flushBuffer();
            //workbook将Excel写入到response的输出流中，供页面下载
            OutputStream os = response.getOutputStream();
            workbook.write(os);

            workbook.close();
            os.close();
        } catch (Exception e) {
            e.printStackTrace();
            return new AsyncResult<>(CommonResult.failed(CommonCodeEnum.FAIL));
        }
        return null;
    }

    private String filterResultNull(String resultStr) {
        if (resultStr == null || resultStr.equals("null")) {
            return "";
        }
        return resultStr;
    }
}
